/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.engine.core.val;

import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.core.determination.builtinimpls.predicate.ExecutePredicate;
import com.inspur.edp.bef.core.determination.builtinimpls.predicate.ExecutePredicateFactory;
import com.inspur.edp.bef.engine.ErrorCodes;
import com.inspur.edp.bef.engine.BefCoreExceptionBase;
import com.inspur.edp.cef.designtime.api.collection.BaseList;
import com.inspur.edp.cef.designtime.api.collection.ValElementCollection;
import com.inspur.edp.cef.designtime.api.operation.ChildValTriggerInfo;
import com.inspur.edp.cef.designtime.api.operation.CommonValidation;
import com.inspur.edp.cef.designtime.api.operation.ExecutingDataStatus;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class ValUtil {

    public static ExecutePredicate buildCanExecute(GspBizEntityObject node, CommonValidation op) {
        if (op.getRequestChildElements() != null && !op.getRequestChildElements().isEmpty()) {
            return new CompatiblePredicate(node, op);
        } else {
            List<ExecutePredicate> predicates = new ArrayList<>();

            buildCanExecuteByChangeTypes(node, op, predicates);
            buildCanExecuteByChildChange(node, op, predicates);

            return ExecutePredicateFactory
                    .getAggregatePredicate(predicates.toArray(new ExecutePredicate[0]));
        }
    }

    private static void buildCanExecuteByChildChange(GspBizEntityObject node, CommonValidation op,
                                                     List<ExecutePredicate> predicates) {
        if (op.getChildTriggerInfo() == null) {
            return;
        }
        for (Map.Entry<String, ChildValTriggerInfo> entry : op.getChildTriggerInfo().entrySet()) {
            String childObjId = entry.getKey();
            IGspCommonObject childObj = node.getChildObjectById(childObjId);
            if (childObj == null) {
                throw new BefCoreExceptionBase(ErrorCodes.BEF_ENGINE_1012, op.getCode(), childObjId);
            }
            ChildValTriggerInfo childDtmTriggerInfo = entry.getValue();
            if (childDtmTriggerInfo.getGetExecutingDataStatus() != null) {
                for (ExecutingDataStatus ds : childDtmTriggerInfo.getGetExecutingDataStatus()) {
                    switch (ds) {
                        case added:
                            predicates.add(ExecutePredicateFactory.getChildAddPredicate(childObj.getCode()));
                            break;
                        case Deleted:
                            predicates.add(ExecutePredicateFactory.getChildDeletePredicate(childObj.getCode()));
                            break;
                        case Modify:
                            List<String> elements = convert2LabelIdList(childObj,
                                    childDtmTriggerInfo.getRequestChildElements());
                            predicates
                                    .add(ExecutePredicateFactory
                                            .getChildModifyPredicate(childObj.getCode(), elements));
                            break;
                    }

                }
            }
        }
    }

    private static void buildCanExecuteByChangeTypes(GspBizEntityObject node,
                                                     CommonValidation op, List<ExecutePredicate> predicates) {
        if (op.getGetExecutingDataStatus() == null) {
            return;
        }
        for (ExecutingDataStatus ds : op.getGetExecutingDataStatus()) {
            switch (ds) {
                case added:
                    predicates.add(ExecutePredicateFactory.getAddPredicate());
                    break;
                case Deleted:
                    predicates.add(ExecutePredicateFactory.getDeletePredicate());
                    break;
                case Modify:
                    List<String> elements = convert2LabelIdList(node, op.getRequestElements());
                    predicates.add(ExecutePredicateFactory.getModifyPredicate(elements));
                    break;
            }
        }
    }

    private static List<String> convert2LabelIdList(IGspCommonObject node, BaseList<String> op) {
        if (op == null || op.isEmpty()) {
            return null;
        }
        List<String> elements = new ArrayList<>(op.size());
        for (String item : op) {
            IGspCommonElement element = node.findElement(item);
            elements.add(element.getLabelID());
        }
        return elements;
    }


    //兼容老版be设计器触发字段选子表
    private static class CompatiblePredicate implements ExecutePredicate {

        private final CommonValidation determination;
        private final GspBizEntityObject gspBizEntityObject;

        public CompatiblePredicate(GspBizEntityObject node, CommonValidation determination) {
            this.determination = determination;
            this.gspBizEntityObject = node;
        }

        @Override
        public boolean test(IChangeDetail change) {
            ExecutingDataStatus temp = ExecutingDataStatus.None;
            switch (change.getChangeType()) {
                case Added:
                    temp = ExecutingDataStatus.added;
                    break;
                case Modify:
                    temp = ExecutingDataStatus.Modify;
                    break;
                case Deleted:
                    temp = ExecutingDataStatus.Deleted;
                    break;
            }
            if (determination.getGetExecutingDataStatus().size() > 0) {
                boolean triggerVaild = false;
                for (ExecutingDataStatus triggerTimePointType : determination.getGetExecutingDataStatus()) {
                    if (temp == triggerTimePointType) {
                        triggerVaild = true;
                    }
                }
                if (!triggerVaild) {
                    return false;
                }
            }
            //触发字段？
            if (this.determination.getRequestElements().getCount() > 0) {
                List<String> list = convert2LabelIdList(gspBizEntityObject,
                        determination.getRequestElements());
                if (com.inspur.edp.cef.entity.changeset.Util.containsAny(change, list)) {
                    return true;
                }
                return false;
            }

            if (this.determination.getRequestChildElements().size() > 0) {
                for (Entry<String, ValElementCollection> pair : this.determination
                        .getRequestChildElements().entrySet()) {
                    IGspCommonObject childNode = this.gspBizEntityObject.getChildObjectById(pair.getKey());
                    List<String> fields = convert2LabelIdList(childNode, pair.getValue());
                    if (com.inspur.edp.cef.entity.changeset.Util.containsChildAny(
                            change, childNode.getCode(), fields.toArray(new String[fields.size()]))) {
                        return true;
                    }
                }
                return false;
            }
            return true;
        }
    }
}
